import { Form, message } from 'antd';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useMount, useRequest } from 'ahooks';

import { useFloatLayer } from '@r-magician/hooks';

const useCRUD = ({
  createService,
  updateService,
  getService,
  deleteService,
  listService,
  messages,
  autoGetList = false,
  refreshDeps = [],
  hooks = {},
}) => {
  const actionRef = useRef(null);
  const [firstEffect, setFistEffect] = useState(false);
  const getMessage = useCallback(
    (type, res) => {
      const fn = messages[type];
      if (!fn) return '操作成功';
      if (typeof fn === 'string') return fn;
      return fn(res);
    },
    [messages],
  );

  const [isEdit, setIsEdit] = useState(false);

  const [editData, setEditData] = useState(null);

  const [form] = Form.useForm();
  const callHooks = useCallback(
    (name, data) => {
      const hook = hooks[name];
      if (hook && typeof hook === 'function') hook(data);
    },
    [hooks],
  );
  const create = useRequest(createService, {
    manual: true,
    onSuccess(data) {
      callHooks('createSuccess', data);
    },
  });

  const update = useRequest(updateService, {
    manual: true,
    onSuccess(data) {
      callHooks('updateSuccess', data);
    },
  });

  const getEditData = useRequest(getService, {
    onSuccess(data) {
      setEditData(data);
      form.setFieldsValue(data);
      callHooks('getSuccess', data);
    },
    manual: true,
  });

  const list = useRequest(listService, {
    manual: true,
    onSuccess(data) {
      if (!firstEffect) {
        setFistEffect(true);
        callHooks('firstEffect', data);
      }
      callHooks('listSuccess', data);
    },
  });

  useEffect(() => {
    if (actionRef.current) {
      actionRef.current?.reload();
    } else {
      list.run();
    }
  }, refreshDeps);

  const reload = useCallback(() => {
    if (actionRef.current) {
      actionRef.current.reload();
    } else {
      list.run();
    }
  }, [actionRef, list]);
  const remove = useRequest(deleteService, {
    manual: true,
    onSuccess(res) {
      const msg = getMessage('remove', res);
      callHooks('deleteSuccess', res);
      message.success(msg, 0.5, () => {
        reload();
      });
    },
  });

  const { visible, confirmLoading, okHandle, open, close } = useFloatLayer({
    onClose: () => {
      form.resetFields();
      setIsEdit(false);
      setEditData(null);
    },
    onConfirm: async () => {
      try {
        await form.validateFields();
        const formData = form.getFieldsValue();
        const res = isEdit
          ? await update.run({
              id: editData.id,
              ...formData,
            })
          : await create.run(formData);
        const msg = !isEdit
          ? getMessage('create', res)
          : getMessage('update', res);
        message.success(msg, 0.5, () => {
          reload();
        });
        return true;
      } catch (error) {
        return false;
      }
    },
  });

  const openHandle = useCallback(
    (data) => {
      if (data) {
        setIsEdit(true);
        getEditData.run(data);
        form.setFieldsValue(data);
      }
      open();
    },
    [open, getEditData, form],
  );

  useMount(() => {
    if (autoGetList) {
      list.run();
    }
  });

  const removeHandle = useCallback(
    (row) => {
      return remove.run(row.id);
    },
    [remove],
  );
  return {
    isEdit,
    openHandle,
    actionRef,
    dataSource: list.data,
    loading: list.loading,
    visible,
    confirmLoading,
    okHandle,
    close,
    form,
    editData,
    removeLoading: remove.loading,
    removeHandle,
    fetchDetail: getEditData.run,
    fetchList: list.run,
  };
};

export default useCRUD;
